For full explanation of coding, map construction, data sources, and analytically choices please see the Methods section. To view code, click the “show” button.

Background and Significance

Transportation barriers pose significant challenges in providing consistent and timely care to patients. In a study using the National Health Interview Survey, nearly 2% of the United States population delayed medical care due to poor access to reliable transportation (Wolfe, McDonald, and Holmes 2020). Lack of reliable transportation can lead to missed appointments, delayed care, and inability to complete recommended treatment plans (Starbird et al. 2019; Syed, Gerber, and Sharp 2013).

Survivors of traumatic injury are a vulnerable patient population and face several barriers to accessing healthcare. Although the initial management of trauma is acute, ongoing survivorship of traumatic injuries require consistent follow up in the outpatient setting. Indeed, transportation barriers are cited in the literature as factors in influencing loss-to-follow up status (Jodoin et al. 2025). There is little insight in the literature regarding the spatial variation of transportation access and patient follow up. Understanding how transportation security varies across Chicago can give insight into how we may improve these barriers for our patient population.

Primary Means of Transportation

I first set to understand the general landscape of car and public transit use in Chicago. The following maps depict the percentages of residents in each block group that do not have a car, drive to work, and use public transportation to get to work. Please see “methods” section for details on map construction and data sources.

The highest block groups with the highest proportion of residents who do not have a car are clustered around the south side, west side, and northern coast. These areas also have the highest block groups who have the highest proportion of residents who take public transit. Block groups with the lowest proportion of residents that drive to work are concentrated in the loop and north eastern side of the city.

Transportation Maps

Car Availability

Drives to Work

Public Transit to Work

Travel Time Analysis

The following depicts the travel time analysis. For a full description of code and methods, see the methods section.

Origins and Destinations

In a travel time analysis, the first step is determining the origins and the destinations. To approximate the travel times experiences in a block group, the origins are the centroid of a block group. A centroid is the geographic center of a polygonal element - in this case a census block group. The destinations are the level one trauma centers within, or in close proximity to, the Chicago city boundary.

Origins and Destinations Maps

Origins: Block Group Centroids

Destinations: Level One Trauma Centers

Methods

Primary Means of Transportation

To understand the primary means of transportation around Chicago, data from the U.S. Census Bureau American Community Survey in 2023 was used for each block group aggregated over 5 years. Maps were constructed by clipping block groups into the Chicago city boundary. The block groups and city boundary were in NAD 83 so they were reprojected to WGS 84 to make the geo-coded trauma locations and for the r5 routing engine.

Population, race and ethnicity, transportation means to work, vehicle availability, and number of households below the poverty level were pulled from the 2023 ACS via the tigris package and converted to percentages.

###----------------------city and block group boundaries---------------------###
# Illinois cities and towns
il_places <- places(state = 'IL',
                    year = 2023,
                    cb = T) #smooths boundry
# filter for Chicago
chiCity <- il_places %>% 
  filter(NAME == 'Chicago')
# Cook County Cencus Block Groups
cook_bgs <- get_acs(geography = 'block group',
                      year = 2023,
                      variables = c(
                          # Population
                            total_pop = "B01003_001",
                          # Race
                            total_race = "B03002_001",
                            white = "B03002_003",
                            black = "B03002_004",
                            native = "B03002_005",
                            asian = "B03002_006",
                            pacific_islander = "B03002_007",
                            hispanic = "B03002_012",
                            other = "B03002_008",
                          # Transportation to work
                            commute_total = "B08301_001",
                            drive_alone = "B08301_003",
                            carpool = "B08301_004",
                            public_transit = "B08301_010",
                            bus = "B08301_011",
                            cta_train = "B08301_012",
                            metra_train = "B08301_013",
                            walked = "B08301_019",
                            bicycle = "B08301_018",
                            home = "B08301_021",
                          # Vehicle availability
                            hh_total = "B25044_001",
                            hh_own = "B25044_002",
                            hh_rent = "B25044_009",
                            own_no_vehicle = "B25044_003",
                            rent_no_vehicle = "B25044_010",
                          # Income level below povery level
                            pov_total = "B17010_001",
                            pov = "B17010_002"),
                      state = 'IL',
                      county = 'Cook',
                      survey = 'acs5',
                      output = 'wide',
                      geometry = 'T')
# calculate percent below federal poverty line and percent race/ethnicity
cook_bgs <- cook_bgs %>% 
  mutate(pwhite = round((whiteE / total_raceE)*100,2), #percentage non- hispanic white
         pblack = round((blackE / total_raceE)*100, 2), #percentage non- hispanic black
         pasian = round((asianE / total_raceE)*100, 2), #percentage non- hispanic asian
         phisp = round((hispanicE / total_raceE)*100, 2), #percentage hispanic
         pother = round(((otherE + nativeE) / total_raceE)*100, 2), #percentage other
         ppov = round((povE/pov_totalE)*100, 2), #percentage under poverty level
         pdrive = round((drive_aloneE/commute_totalE)*100, 2), #percentage drive to work
         ppubtrans = round((public_transitE/commute_totalE)*100, 2), #percentage take public transit to work
         pbus = round((busE/commute_totalE)*100, 2), #percentage bus to work
         pcta_train = round((cta_trainE/commute_totalE)*100, 2), #percentage take L to work
         pmetra_train = round((metra_trainE/commute_totalE)*100, 2), #percentage take long distance train to work
         pbike = round((bicycleE/commute_totalE)*100, 2), #percentage bike to work
         pwalk = round((walkedE/commute_totalE)*100, 2), #percentage walk to work
         pwo_vehicel = round(((own_no_vehicleE + rent_no_vehicleE)/hh_totalE)*100, 2), #percentage without a vehicle
        ) %>%
  dplyr::select(GEOID, NAME, total_popE, pwhite, pblack, 
                pasian, phisp, pother, ppov, 
                pdrive, ppubtrans, pbus, 
                pcta_train, pmetra_train, pbike, pwalk, pwo_vehicel, geometry) #select key variables 
# Clip tracts using Chicago city boundary
chi_bgs <- ms_clip(target = cook_bgs,
                     clip = chiCity,
                     remove_slivers = T)
chi_bgs <- st_make_valid(chi_bgs)
#check projections
st_crs(chiCity) # NAD83 (4269) - Geographic reference system
st_crs(chi_bgs) # NAD83 (4269) - Geographic reference system
st_crs(trauma_geo) # WGS 84 (4326) - Geographic reference system
#align to WGS 84
chiCity <- st_transform(chiCity, 4326)
chi_bgs <- st_transform(chi_bgs, 4326)

Box plots were constructed to visualize the distribution of percentages of residents in each block group that do not have a car, drive to work, and use public transportation to get to work. While the percentage of people driving to work is fairly normal, the percentage who take public transit and the percentage who do not have a car is not. Therefore, I opted to display the data with Jenks breaks - this would allow fair comparison across graphs without having to standardize non-normal data.

I prefer the ggplot package over the tmap for such granular divisions as block groups because I feel the resolution to be better. ggplot does not have an automatic jenks function though, so i had to compute them manually with the ClassInt package in R and specifically extract the “breaks” from the classIntervals function. I then created a data frame with categorized data by cutting each column by the computed jenks breaks. I now had sorted data by jenks ready for ggplotting. While this took extra time and research, the map appears cleaner than tmap.

###--------------------------means of transportation-------------------------###
#quick exploration of means of transportation to work
ggplot(data = chi_bgs,
       mapping = aes(y = pdrive)) +
  geom_boxplot(coef = 1.5)

ggplot(data = chi_bgs,
       mapping = aes(y = ppubtrans)) +
  geom_boxplot(coef = 1.5)

ggplot(data = chi_bgs,
       mapping = aes(y = pwo_vehicel)) +
  geom_boxplot(coef = 1.5)

#percentage of driving to work is fairly normal but the percentage who take public transit
#and the percentage who do not have a car is not; will use jenks to display
### --- plot with ggplot --- ###
#compute jenks
jenks_breaks_pdrive <- classIntervals(chi_bgs$pdrive, n = 5, style = "jenks")$brks
jenks_breaks_ppubtrans <- classIntervals(chi_bgs$ppubtrans, n = 5, style = "jenks")$brks
jenks_breaks_pwo_vehicle <- classIntervals(chi_bgs$pwo_vehicel, n = 5, style = "jenks")$brks
#categorize data frames
chi_bgs_jenks <- chi_bgs %>%
  mutate(drive_cat = cut(pdrive, breaks = jenks_breaks_pdrive, include.lowest = TRUE, dig.lab = 5)) %>% 
  mutate(pubtrans_cat = cut(ppubtrans, breaks = jenks_breaks_ppubtrans, include.lowest = TRUE, dig.lab = 5)) %>% 
  mutate(wo_vehicle_cat = cut(pwo_vehicel, breaks = jenks_breaks_pwo_vehicle, include.lowest = TRUE, dig.lab = 5))
#plot with jenks
#percentage who drive
drive_map <- ggplot() +
  geom_sf(
    data = chi_bgs_jenks,
    aes(fill = drive_cat),
    color = NA) +
  scale_fill_brewer(
    palette = "OrRd",
    name = "Percentage") +
  labs(
    title = "Percentage Who Drive to Work",
    caption = "Source: ACS 2023 5-year estimates (Table B08301)") +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = c(0.95, 0.80),
    legend.background = element_rect(
      fill = "white",
      color = "black"),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10),
    plot.title = element_text(
      face = "bold",
      size = 16,
      hjust = 0.5),
    panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank())

#percentage who do not have a car
car_map <- ggplot() +
  geom_sf(
    data = chi_bgs_jenks,
    aes(fill = wo_vehicle_cat),
    color = NA) +
  scale_fill_brewer(
    palette = "OrRd",
    name = "Percentage") +
  labs(
    title = "Percentage Who Do Not Have a Car",
    caption = "Source: ACS 2023 5-year estimates (Table B25044)") +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = c(0.95, 0.80),
    legend.background = element_rect(
      fill = "white",
      color = "black"),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10),
    plot.title = element_text(
      face = "bold",
      size = 16,
      hjust = 0.5),
    panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank())

#percentage who do not have a car
pubtrans_map <- ggplot() +
  geom_sf(
    data = chi_bgs_jenks,
    aes(fill = pubtrans_cat),
    color = NA) +
  scale_fill_brewer(
    palette = "OrRd",
    name = "Percentage") +
  labs(
    title = "Percentage Who Take Public Transit to Work",
    caption = "Source: ACS 2023 5-year estimates (Table B08301)") +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = c(0.95, 0.80),
    legend.background = element_rect(
      fill = "white",
      color = "black"),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10),
    plot.title = element_text(
      face = "bold",
      size = 16,
      hjust = 0.5),
    panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank())

Network Analysis

Much of my network analysis was derived from the transportation chapter in Geocomputation with R (Lovelace, Nowosad, and Muenchow 2019).

Origin and Destination Designation

The first step of travel time analysis is to determine origin and destinations. My origins will be the centroid of each block group. This makes an assumption that each person in that block group experiences similar transit times. Although this may be valid for small block groups this is obviously less accurate for very large ones. Given that large block groups are few and reflect low population density I believe this to be an acceptable limitation. The alternative, using blocks or individual residence addresses, is far too large of a computational burden to be feasible. Any block groups with no recorded populations are filtered out.

The destinations are level on trauma centers in Chicago as determined by the Illinois Department of Public Health. Level one trauma centers accept the highest acuity of trauma patients, and therefore will serve the population of interest - trauma patients with such sifficient injury that they need regular follow up with a trauma surgeon. I only included 9 trauma centers within or in close proximity of the city boundary by filtering the full, geo-coded trauma center list used in class. This included:

  • Advocate Christ Medical Center

  • Ascension Saint Francis

  • Mount Sinai Hospital

  • Advocate Illinois Masonic Medical Center

  • Advocate Lutheran General Hospital

  • John H. Stroger, Jr. Hospital of Cook County

  • Loyola University Medical Center

  • Northwestern Memorial Hospital

  • University of Chicago

###--------------------------origins and destinations------------------------###
#origins - centroids
chi_bgcentroids <- st_centroid(chi_bgs)
chi_bgcentroids <- chi_bgcentroids %>% 
  filter(total_popE > 0) #filter out centroids without any populations
tmap_mode('view')
origins_map <- tm_shape(chi_bgs) +
  tm_borders() +
  tm_shape(chi_bgcentroids) +
  tm_dots(fill = "blue",
          size = 0.25)
#destinations - trauma centers
trauma_geo$facility <- as.character(trauma_geo$facility)
adult_level_one <- trauma_geo %>% 
  filter(facility %in% c(
    'Advocate Christ Medical Center',
    'Ascension Saint Francis - Emergency Room',
    'Mount Sinai Hospital',
    'Advocate Illinois Masonic Medical Center',
    'Advocate Lutheran General Hospital',
    'John H. Stroger, Jr. Hospital of Cook County',
    'Loyola University Medical Center',
    'Northwestern Memorial Hospital',
    'University of Chicago Emergency Department and Trauma Center'))
destinations_map <- tm_shape(chiCity) +
  tm_borders() +
  tm_shape(adult_level_one) +
  tm_dots(fill = "darkgreen",
          size = 0.25)

Routing Network Construction

References

Jodoin, Zachary, Daanish Sheikh, Cameron Atkinson, Loc Uyen Vo, Alvaro Moreira, Christina Brady, and Boris Zelle. 2025. “Paediatric ballistic fracture patients: who has poor follow-up and why?” International Orthopaedics 49 (6): 1451–60. https://doi.org/10.1007/s00264-025-06506-3.
Lovelace, Robin, Jakub Nowosad, and Jannes Muenchow. 2019. Chapter 13 Transportation | Geocomputation with R. https://r.geocompx.org/transport.html.
Starbird, Laura E., Caitlin DiMaina, Chun-An Sun, and Hae-Ra Han. 2019. “A Systematic Review of Interventions to Minimize Transportation Barriers Among People with Chronic Diseases.” Journal of Community Health 44 (2): 400–411. https://doi.org/10.1007/s10900-018-0572-3.
Syed, Samina T., Ben S. Gerber, and Lisa K. Sharp. 2013. “Traveling Towards Disease: Transportation Barriers to Health Care Access.” Journal of Community Health 38 (5): 976–93. https://doi.org/10.1007/s10900-013-9681-1.
Wolfe, Mary K., Noreen C. McDonald, and G. Mark Holmes. 2020. “Transportation Barriers to Health Care in the United States: Findings from the National Health Interview Survey, 19972017.” American Journal of Public Health 110 (6): 815–22. https://doi.org/10.2105/AJPH.2020.305579.